package com.leenmvc.core.base;

import com.leenmvc.core.dao.communal.Dialect;
import com.leenmvc.core.enums.EntityInfoEnum;
import com.leenmvc.core.security.entity.core.*;
import com.leenmvc.core.utils.ClassUtil;
import com.leenmvc.core.utils.StringUtils;
import com.leenmvc.core.utils.spring.SpringContextUtils;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 基础类
 *
 * @Author: JohnCoding
 * @Description:
 * @date: 2020/1/8 9:00
 */
public class BaseEntity {

    private final static Logger logger = LoggerFactory.getLogger(BaseEntity.class);

    /**
     * 通过类名进行存储
     */
    public static Map<Class, EntityInfo> classInfo = Collections.synchronizedMap(new HashMap<>());

    /**
     * 通过类名字符串存储
     */
    public static Map<String, EntityInfo> entityMap = Collections.synchronizedMap(new HashMap<>());

    /**
     * 将实体字段和数据库字段的驼峰下划线互转字符串全部存储起来
     */
    private static Map<String, String> humpLine = Collections.synchronizedMap(new HashMap<>());

    /**
     * 根据字段名字找到字段对象
     */
    private static Map<String, Field> fieldNameMap = Collections.synchronizedMap(new HashMap<>());

    static {
        // 继承了BaseEntity的类使用反射获取
        Reflections reflections = new Reflections("com.leenmvc.core.security.entity", "com.leenmvc.iot.entity");

        Set<Class<?>> entitySet = new HashSet<>();
        Set<Class<? extends BaseEntity>> subTypes = reflections.getSubTypesOf(BaseEntity.class);
        entitySet.addAll(subTypes);

        // 未继承BaseEntity的类直接添加
        entitySet.add(SysMenu.class);
        entitySet.add(SysApiResult.class);
        entitySet.add(SysDept.class);
        entitySet.add(SysFileUpload.class);
        entitySet.add(SysRole.class);

        for (Class<?> entity : entitySet) {
            EntityInfo entityInfo = new EntityInfo(entity);
            String name = StringUtils.lowercaseFirstChar(entity.getSimpleName());
            entityInfo.setTableComment(ClassUtil.getTableComment(entity));
            // 设置实体
            try {
                entityInfo.setEntityClass(entity);
            } catch (Exception e) {

            }

            // 设置excel实体
            try {
                entityInfo.setExcelEntity(ClassUtil.getExcelEntity(entity));
            } catch (Exception e) {

            }


            try {
                entityInfo.setDaoClass(SpringContextUtils.getBean(name + "Dao").getClass());
            } catch (Exception e) {

            }
            try {
                entityInfo.setServiceClass(SpringContextUtils.getBean(name + "Service").getClass());
            } catch (Exception e) {

            }
            try {
                entityInfo.setControllerClass(SpringContextUtils.getBean(name + "Controller").getClass());
            } catch (Exception e) {

            }
            for(Field field: entity.getDeclaredFields()) {
                String line = ClassUtil.humpToLine(field.getName());
                String hump = field.getName();
                humpLine.put(line, hump);
                humpLine.put(hump, line);
                fieldNameMap.put(entity.getSimpleName() + "." + hump, field);
            }

            entityInfo.setDialect(ClassUtil.getDialect(entity));
            entityInfo.setTableName(ClassUtil.getTableName(entity));
            entityInfo.setPrimaryFieldName(ClassUtil.getPrimaryFieldName(entity));
            entityInfo.setPrimaryColumnName(ClassUtil.getPrimaryColumnName(entity));
            entityInfo.setSchema(ClassUtil.getSchema(entity));
            entityInfo.setSourceGroup(ClassUtil.getSourceGroup(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD, ClassUtil.getFillFields(entity));
            entityInfo.putFieldArray(EntityInfoEnum.DB_FIELD_ARR, ClassUtil.getDBFields(entity));
            entityInfo.putFieldStrArr(EntityInfoEnum.DB_FIELD_STR, ClassUtil.getDBFieldStrArr(entity));
            entityInfo.putFieldStrArr(EntityInfoEnum.COLUMNS,  ClassUtil.getColumnsArr(entity));
            entityInfo.putFieldStrArr(EntityInfoEnum.FIELDS,  ClassUtil.getFieldsArr(entity));
            entityInfo.putFieldStrArr(EntityInfoEnum.FILL_FIELD_COLUMN_LIST,  ClassUtil.getFillFieldColumnArr(entity));
            entityInfo.putFieldStrArr(EntityInfoEnum.COLUMNS_FOR_SQL, ClassUtil.getColumnsSQL(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_ONE_FIELD_IN, ClassUtil.getFillFieldsOneFieldIn(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_ONE_TO_ONE, ClassUtil.getFillFieldsOneToOne(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_ONE_TO_MULTIPLE, ClassUtil.getFillFieldsOneToMultiple(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_QUERY, ClassUtil.getFillFieldDefaultQuery(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_FIELD_IN_QUERY, ClassUtil.getFillFieldOneFieldInDefaultQuery(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_TO_ONE_QUERY, ClassUtil.getFillFieldOneToOneDefaultQuery(entity));
            entityInfo.putFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_TO_MUL_QUERY, ClassUtil.getFillFieldOneToMulDefaultQuery(entity));
            logger.info("初始化实体类：" + entity.getSimpleName() + "到内存中");
            classInfo.put(entity, entityInfo);
            entityMap.put(name, entityInfo);
        };
        classInfo = Collections.unmodifiableMap(classInfo);
        entityMap = Collections.unmodifiableMap(entityMap);
        humpLine = Collections.unmodifiableMap(humpLine);
        fieldNameMap = Collections.unmodifiableMap(fieldNameMap);
    }

    /**
     * 根据英文名称获取字段
     *
     * @param name
     * @return
     */
    public static Field getField(String name) {
        return fieldNameMap.get(name);
    }

    public static Field[] getFieldInDefaultQueryFields(Class<?> cls) {
        return classInfo.get(cls).getFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_FIELD_IN_QUERY);
    }

    public static Field[] getFillFieldDefaultQueryFields(Class<?> cls) {
        return classInfo.get(cls).getFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_QUERY);
    }

    public static Field[] getOneToOneDefaultQueryFields(Class<?> cls) {
        return classInfo.get(cls).getFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_TO_ONE_QUERY);
    }

    public static Field[] getOneToMulDefaultQueryFields(Class<?> cls) {
        return classInfo.get(cls).getFieldArray(EntityInfoEnum.FILL_FIELD_DEFAULT_ONE_TO_MUL_QUERY);
    }

    /**
     * 获取拼装SQL语句的字符串数组
     *
     * @param cls
     * @return
     */
    public static Field[] getFillFieldByType(Class<?> cls, EntityInfoEnum fieldType) {
        return classInfo.get(cls).getFieldArray(fieldType);
    }


    /**
     * 获取拼装SQL语句的字符串数组
     *
     * @param cls
     * @return
     */
    public static String[] getColumnsForSql(Class<?> cls) {
        return classInfo.get(cls).getFieldStrArr(EntityInfoEnum.COLUMNS_FOR_SQL);
    }

    /**
     * 获取字段列表
     *
     * @param entityInfoEnum
     * @param cls
     * @return
     */
    public static List<String> getFields(EntityInfoEnum entityInfoEnum, Class<?> cls) {
        List<String> resultList = new ArrayList<>();
        String[] fieldList = classInfo.get(cls).getFieldStrArr(entityInfoEnum);
        for (String field : fieldList) {
            resultList.add(field);
        }
        return resultList;
    }

    public static Field[] getDBFields(Class<?> cls) {
        return classInfo.get(cls).getFieldArray(EntityInfoEnum.DB_FIELD_ARR);
    }

    public static String getTableName(Class<?> cls) {
        return classInfo.get(cls).getTableName();
    }

    public static Class<?> getExcelEntity(Class<?> cls) {
        return classInfo.get(cls).getExcelEntity();
    }

    public static String getPrimaryFieldName(Class<?> cls) {
        return classInfo.get(cls).getPrimaryFieldName();
    }

    public static String getPrimaryColumnName(Class<?> cls) {
        return classInfo.get(cls).getPrimaryColumnName();
    }

    public static Dialect getDialect(Class<?> cls)  {
        return classInfo.get(cls).getDialect();
    }

    public static String getSchema(Class<?> cls) {
        return classInfo.get(cls).getSchema();
    }

    public static String getSourceGroup(Class<?> cls) {
        return classInfo.get(cls).getSourceGroup();
    }

    public static String humpLine(String humpline) {
        return humpLine.get(humpline);
    }

    public static String humpLine(Field humpline) {
        return humpLine.get(humpline.getName());
    }

}
